import createElement from "./createElement";
import patchVnode from "./patchVnode";
/**
 * 
 * @param {object} parentElm Dom节点 
 * @param {Array} oldCh oldVnode的子节点数组
 * @param {Array} newCh newVnode的子节点数组
 */
export default function updateChildren(parentElm, oldCh, newCh) {
    console.log('updateChildren()');
    console.log(oldCh, newCh);
    // 四个指针
    // 旧前
    let oldStartIdx = 0;
    // 新前
    let newStartIdx = 0;
    // 旧后
    let oldEndIdx = oldCh.length - 1;
    // 新后
    let newEndIdx = newCh.length - 1;

    // 指针指向的四个节点
    // 旧前节点
    let oldStartVnode = oldCh[0];
    // 旧后节点
    let oldEndVnode = oldCh[oldEndIdx];
    // 新前节点
    let newStartVnode = newCh[0];
    // 新后节点
    let newEndVnode = newCh[newEndIdx];

    let keyMap = null;

    while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
        console.log('**循环中**');
        // 首先应该不是判断四种命中，而是略过已经加了undefined标记的项
        if (oldStartVnode === null || oldCh[oldStartIdx] === undefined) {
            oldStartVnode = oldCh[++oldStartIdx];
        } else if (oldEndVnode === null || oldCh[oldStartIdx] === undefined) {
            oldEndVnode = oldCh[--oldEndIdx];
        } else if (newStartVnode === null || newCh[newStartIdx] === undefined) {
            newStartVnode = newCh[++newStartIdx];
        } else if (newEndVnode === null || newCh[newEndIdx] === undefined) {
            newEndVnode = newCh[--newEndIdx];
        } else if (checkSameVnode(oldStartVnode, newStartVnode)) {
            // 新前与旧前
            console.log('① 新前与旧前 命中');
            // 精细化两个节点 oldStartVnode 现在和newStartVnode一样了
            patchVnode(oldStartVnode, newStartVnode);
            // 移动指针，改变指针指向的节点，这表示这两个指针都处理(比较)完了
            oldStartVnode = oldCh[++oldStartIdx]
            newStartVnode = newCh[++newStartIdx]
        } else if (checkSameVnode(oldEndVnode, newEndVnode)) {
            // 新后与旧后
            console.log('② 新后与旧后 命中');
            // 精细化比较
            patchVnode(oldEndVnode, newEndVnode)
            oldEndVnode = oldCh[--oldEndIdx]
            newEndVnode = newCh[--newEndIdx]
        } else if (checkSameVnode(oldStartVnode, newEndVnode)) {
            // 新后与旧前
            console.log('③ 新后与旧前 命中');
            patchVnode(oldStartVnode, newEndVnode)

            // 当③ 新后与旧前 命中的时候，此时需要移动节点。移动 新后（旧前）指向的这个节点到老节点的 旧后的后面。
            // 移动节点：只要插入一个已经在DOM树上的节点，就会被移动
            parentElm.insertBefore(oldStartVnode.elm, oldEndVnode.elm.nextSibling);
            oldStartVnode = oldCh[++oldStartIdx]
            newEndVnode = newCh[--newEndIdx]
        } else if (checkSameVnode(newStartVnode, oldEndVnode)) {
            // 新前与旧后
            console.log('④ 新前与旧后 命中');
            patchVnode(oldEndVnode, newStartVnode)

            // 当④新前与旧后命中的时候，此时要移动节点。移动 新前（旧后）指向的这个节点到老节点的 旧前的前面。
            // 移动节点：只要插入一个已经在DOM树上的节点，就会被移动。
            parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm)
            oldEndVnode = oldCh[--oldEndIdx]
            newStartVnode = newCh[++newStartIdx]
        } else {
            // 四种都没有匹配到，都没有命中
            console.log('四种都没有命中');
            // 寻找 keyMap , 一个映射对象，就不用每次都遍历old对象了
            if (!keyMap) {
                keyMap = {};
                // 记录oldVnode中的节点出现的key
                // 从oldStartIdx开始到oldEndIdx结束，创建keyMap
                for (let i = oldStartIdx; i <= oldEndIdx; i++) {
                    const key = oldCh[i].key
                    if (key !== undefined) {
                        keyMap[key] = i;
                    }
                }
            }
            console.log(keyMap);
            // 寻找当前项（newStartIdx）在keyMap中映射的序号
            const idxInOld = keyMap[newStartVnode.key]
            if (idxInOld === undefined) {
                // 如果idxInOld是undefined,说明是全新的项，要插入
                // 被加入的项（就是newStartVnode这项）现不是真正的DOM节点
                parentElm.insertBefore(createElement(newStartVnode), oldStartVnode.elm)
            } else {
                // 说明不是全新的项，要移动
                const elmToMove = oldCh[idxInOld];
                patchVnode(elmToMove, newStartVnode)
                    // 把这项设置为undefined,表示我已经处理完这项了
                oldCh[idxInOld] = undefined
                    // 移动，调用insertBefore也可以实现移动 (移动到旧前之前)
                parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm)
            }
            newStartVnode = newCh[++newStartIdx]
        }
    }
    // 循环结束
    if (newStartIdx <= newEndIdx) {
        // 说明newVnode还有剩余节点没有处理，所以要添加这些节点
        for (let i = newStartIdx; i <= newEndIdx; i++) {
            // 这是一个优化写法
            // insertBefore方法可以自动识别null,如果是null,就会自动排到队尾，和appendChild一致
            console.log(oldCh[oldStartIdx], 'oldCh[oldStartIdx]');
            const ele = oldCh[oldStartIdx] === undefined ? null : oldCh[oldStartIdx].elm;
            parentElm.insertBefore(createElement(newCh[i]), ele);
        }
    } else if (oldStartIdx <= oldEndIdx) {
        // 说明oldVnode还有剩余节点没有处理，所以要删除这些节点
        for (let i = oldStartIdx; i <= oldEndIdx; i++) {
            if (oldCh[i]) {
                parentElm.removeChild(oldCh[i].elm)
            }
        }
    }
}
// 判断是否是同一个节点
function checkSameVnode(a, b) {
    return a.sel === b.sel && a.key === b.key;
}